﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using DuelQuizzServer.contrats;
using DuelQuizzServer.exception;
using System.Windows;

namespace DuelQuizzServer.services
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class DuelQuizzServices : IDuelQuizzService
    {
        /* Static members*/
        private static Random rnd = new Random();
        private static int last_insert_party_id = 1;
        private static Object _lock = new Object();
        private static List<string> users = new List<string>();

        /* Users members */
        IDuelQuizzServiceCallback callback;
        private bool is_logged = false;
        private User user;

        #region Events
            internal static event Action EventNewPartyCreated;
            internal static event Action<int> EventNewNotification;
            internal static event Action<int,int> EventRequestDuelWith;
            internal static event Action<int, int> EventStartDuel;

            private void WS_EventNewPartyCreated() { callback.refreshListParties(); }
            private void WS_EventNewNotification(int user_id) { if( user_id == user.id) callback.refreshNotifications(); }
            private void WS_EventRequestDuelWith(int j1, int j2) { if (j2 == user.id) callback.duelRequestedBy(j1, j2); }
            private void WS_EventStartDuel(int j1, int j2) { if (j1 == user.id || j2 == user.id) callback.startDuel(); }
        #endregion

        public void ServiceConnection()
        {
            callback = OperationContext.Current.GetCallbackChannel<IDuelQuizzServiceCallback>();

            EventNewPartyCreated += WS_EventNewPartyCreated;
            EventNewNotification += WS_EventNewNotification;
            EventRequestDuelWith += WS_EventRequestDuelWith;
            EventStartDuel += WS_EventStartDuel;
            /*if (callback != null)
                callback.test();*/
        }

        public void ServiceDeconnection()
        {
            EventNewPartyCreated -= WS_EventNewPartyCreated;
            EventNewNotification -= WS_EventNewNotification;
            users.Remove(user.username);
        }


        #region Users Actions
            public void createUser(string username, string password, string account_type, string country)
            {
                User u = new User();
                u.username = username;
                u.password = password;
                u.account_type = account_type;
                u.country = country;
                u.creation_date = DateTime.Now;

                Entities c = new Entities();
                c.User.Add(u);
                c.SaveChanges();
            }

            public User login(string username, string password)
            {
                User u = User.login(username,password);
                if (u != null)
                {
                    this.user = u;
                    this.is_logged = true;
                    users.Add(this.user.username);
                    return u;
                }
                 else return null;
                
            }

            public Notification[] getNotifications()
            {
                if (this.is_logged && this.user != null)
                    return user.notifications.ToArray();
                else
                    return new Notification[0];
            }

            public void creerNotification(int targeted_player, string type)
            {
                if (!this.is_logged || this.user == null) return;

                User destination_user = User.find(user.id);
                if (destination_user == null) throw new PlayerNotFound();

                Notification notif = new Notification();
                notif.user_id = targeted_player;
                notif.user_source_id = user.id;
                notif.date = DateTime.Now;
                notif.type = type;
                if (type == "friend_request")
                {
                    notif.message = user.username + " veut être votre ami.";
                }
                else
                {
                    notif.message = user.username + " vous veut du mal !.";
                }

                Notification.add(notif);
                if (EventNewNotification != null) EventNewNotification(targeted_player);
            }

            public void saveResult(int user_id, int opponent_id, int points)
            {
                Result result = new Result();
                result.user_id = user_id;
                result.opponent_id = opponent_id;
                result.points = points;
                result.date = DateTime.Now;
                user.score += points;

                User.update(user);
                Result.add(result);

            }

            public User getUser(int id)
            {
                return User.find(id);
            }

            public Leaderboard getLeaderBoard() {
                return new Leaderboard(user);
            }

            public bool addFriend(int friend_id)
            {
                if (user == null || is_logged == false) return false;

                //return user.addFriend(friend_id);
                return Friend.addFriend(friend_id, user.id);
            }

            public User getUserWithUsername(string pseudo)
            {
                return User.find(pseudo);
            }

            public User[] getFriends()
            {
                if (user == null || is_logged == false) return new User[0];

                return Friend.getFriend(user.id).ToArray();
            }

            public void requestDuelWith(int j1, int j2)
            {

            }

            public void answerRequestForDuel(int j1, int j2, string answer)
            {
                if (answer == "YES")
                {
                    
                }
                else
                {

                }
            }

            public void requestRandomDuel(int id)
            {
                List<string> tmp = users;
                tmp.Remove(user.username);
                int r = rnd.Next(tmp.Count);
                EventRequestDuelWith(id, r);
            }
        #endregion

        #region Questions Actions
            public List<Category> getAllCategories()
            {
                return Category.getCategories(0);
            }

            public List<Category> getRandomCategories(int limit)
            {
                return Category.getCategories(limit);
            }

            public void addCategory(string name, string description)
            {
                Category category = new Category();
                category.name = name;
                category.description = description;
                Category.add(category);
            }

            public Category getCategory(int index)
            {
                Category c = Category.find(index);
                return c;
            }

            public List<Question> getQuestionsFromCategory(int category_id, int quantity)
            {
                return Question.getQuestionsFromCategory(category_id, quantity);
            }


            public bool addQuestion(Question question, int category_id)
            {
                Category category = Category.find(category_id);
                if (category == null) return false;
                question.creation_date = DateTime.Now;
                question.category = category;
                question.category_id = category.id;
                return Question.add(question);
            }

            public void readAllNotifications()
            {
                user.readNotifications();
            }
        #endregion

        #region Party Actions
            public void createParty(string title)
            {
                lock (_lock)
                {
                    if (title == "")
                        if (user != null) title = "#" + last_insert_party_id + " Party of " + user.username;
                        else title = "#" + last_insert_party_id + " Party of Nobody :O";

                    Party party = new Party(last_insert_party_id++, title);
                    party.Title = title;
                    if (user != null)
                        party.addPlayer(user);

                    if (EventNewPartyCreated != null) EventNewPartyCreated();
                    ///return party;
                }
               
            }

            public void addPlayerToParty(int player_id ,int party_id)
            {
                Party party = Party.find(party_id);
                if (party == null) return;
                
                User player = User.find(player_id);
                if (player == null) return;

                party.addPlayer(player_id);                    
            }

            public void removePlayerToParty(int player_id, int party_id)
            {
                Party party = Party.find(party_id);
                if (party == null) return;

                User player = User.find(player_id);
                if (player == null) return;

                party.removePlayer(player_id); 
            }

            public User[] getPlayersFromParty(int party_id)
            {
                Party party = Party.find(party_id);
                if (party == null) return new User[0];
                else return party.Player_list.ToArray();
            }

            public Party[] getParties()
            {
                return Party.Parties.ToArray();
            }

            public void startGame()
            {
                throw new NotImplementedException();
            }

            public void endGame()
            {
                throw new NotImplementedException();
            }

        #endregion


    }
}
